
#region Using region
using System;
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using System.Collections.Specialized;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;


using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using JigLibX.Math;
using JigLibX.Utils;
using sqengine.PhysicObjects;
using JigLibX.Vehicles;
using System.Diagnostics;

using TomShane.Neoforce.Controls;


using sqengine.Engine;
using sqengine.Components;

using sqengine.Engine.Common;
using sqengine.Engine.Effects.Bloom;



using SqEngine.Components;

using SqEngine.Audio;
using SqEngine;
using PK3Model;

using Microsoft.Win32.SafeHandles;

#endregion
/*
 * !!! NOTE: Before you use this program's source you MUST accept the license !!! 
 * I spend lot of this to build this, please don't steel my work!! Thank you
 * squid (squid@stormwind.it)
 * 
 * 
 * 
 * Microsoft Reciprocal License (Ms-RL)
 *
 * This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
 * 
 * 1. Definitions
 * 
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
 * 
 * A "contribution" is the original software, or any additions or changes to the software.
 * 
 * A "contributor" is any person that distributes its contribution under this license.
 * 
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 
 * 2. Grant of Rights
 * 
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
 * 
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
 * 
 * 3. Conditions and Limitations
 * 
 * (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
 * 
 * (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
 * 
 * (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
 * 
 * (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
 * 
 * (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
 * 
 * (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
 */


namespace sqengine
{


    #region ImmovableSkinPredicate
    class ImmovableSkinPredicate : CollisionSkinPredicate1
    {
        public override bool ConsiderSkin(CollisionSkin skin0)
        {
            if (skin0.Owner != null && !skin0.Owner.Immovable && !(skin0.Owner is Character))
                return true;
            else
                return false;
        }
    }
    #endregion


    partial class sqengine : Microsoft.Xna.Framework.Game
    {

        //Dichiarazioni principali
        private const int WIDTH = 800;
        private const int HEIGHT = 600;

        private GraphicsDeviceManager graphics;
        private ContentManager content;
        private CfgSave sqconfig = new CfgSave();
        private PlayerStats _player;
        private SpriteBatch spriteBatch;
        private BasicObject prev_obj;




        public AdvancedContent AdContent { get { return adcontent; } }


        public Microsoft.Xna.Framework.Rectangle GetSafeArea { get { return GraphicsDevice.Viewport.TitleSafeArea; } }

        private List<PK3_Model> BotList = new List<PK3_Model>();

        public List<PK3_Model> GetBotList { get { return BotList; } }

        Random random = new Random();

        ParticleSystem explosionParticles;
        ParticleSystem explosionSmokeParticles;
        ParticleSystem projectileTrailParticles;
        ParticleSystem smokePlumeParticles;
        ParticleSystem fireParticles;



        // The sample can switch between three different visual effects.
        enum ParticleState
        {
            Explosions,
            SmokePlume,
            RingOfFire,
        };

        ParticleState currentState = ParticleState.Explosions;




        #region Fonts

        private SpriteFont fnt_verdana;
        private SpriteFont fnt_miramo;
        private SpriteFont fnt_console;

        #endregion


        List<Projectile> projectiles = new List<Projectile>();
        TimeSpan timeToNextProjectile = TimeSpan.Zero;

        #region Components
        private GamerServicesComponent cmp_services;
        private GuideX cmp_guidex;
        private FrameRateCounter physStats;
        private MapInfoDrawer mapinfo;

        private PresentationSystem introengine;
        private SqAudio audioengine;
        private AudioManager audiomanager;
        private AdvancedContent adcontent;

        private CrosshairSprite crosshair;
        private KeysManager keyboardmanager;
        private ScreenShotComponent screenshotmanager;
        private SaveManager SaveMan = new SaveManager();
        private TargetManager TargetMan;
        private Hud hud;
        private AwardsComponent award_cmp;
        private MessagesSystem msgs_sys;
        private MediaPlayerSystem mediaplayer_sys;
        private ContentLoadingDrawer contentloading_cmp;
        private ChatComponent chat_cmp;
        private Manager gui_manager;
        private GUIComponent UI_cmd;
        private BloomComponent eff_bloom;
        private GPSSystem cmp_gpssys;
        private ScoreComponent cmp_scoreboard;


        //private ConfigEngine config;
        #endregion

        public KeysManager Keyman { get { return keyboardmanager; } }


        Model boxModel, sphereModel, capsuleModel, compoundModel, terrainModel, cylinderModel, planeModel;



        CharacterObject character;
        public HeightmapObject heightmapObj;
        public PlaneObject planeObj;
        private SkyDome skydome;

        public SkyDome CurrentSkydome { get { return skydome; } set { skydome = value; } }

        private FPSWeapon fps_weapon;



        public PlayerStats CurrentPlayer { get { return _player; } set { _player = value; } }

        float timeStep = 0;


        #region Physics System and Camera
        public PhysicsSystem physicSystem;
        DebugDrawer debugDrawer;
        Camera camera;
        ConstraintWorldPoint objectController = new ConstraintWorldPoint();
        ConstraintVelocity damperController = new ConstraintVelocity();
        #endregion

        bool isPickEnabled = true;
        bool isPlayerEnabled = true;
        bool isIntroEnabled = false;
        public bool isIntroPlaying = false;

        public bool isDebugEnabled
        {
            get
            {
                bool dbg = false;
                bool.TryParse(ConsoleGetVar(VAR_SQDEBUG), out dbg);
                return dbg;
            }
            set
            {
                ConsoleSetVar(VAR_SQDEBUG, value.ToString());
            }
        }

        public bool isTraceLogEnabled
        {
            get
            {
                bool tracelg = false;
                bool.TryParse(ConsoleGetVar(VAR_SQTRACELOG), out tracelg);
                return tracelg;
            }
            set
            {
                ConsoleSetVar(VAR_SQTRACELOG, value.ToString());
            }
        }

        string IntroFile;


        #region Audio Engine
        private AudioEngine audioEngine;
        private WaveBank waveBank;
        private SoundBank soundBank;

        private Cue cue;
        private AudioEmitter emitter = new AudioEmitter();
        private AudioListener listener = new AudioListener();
        #endregion

        public sqengine(string[] args)
        {
            Content.RootDirectory = "Content";

            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);

            graphics.MinimumPixelShaderProfile = ShaderProfile.PS_3_0;
            graphics.MinimumVertexShaderProfile = ShaderProfile.VS_3_0;


            adcontent = new AdvancedContent(this, Content);

            graphics.SynchronizeWithVerticalRetrace = true;
            this.IsFixedTimeStep = true;
            graphics.SynchronizeWithVerticalRetrace = false;
            this.IsFixedTimeStep = false;




            graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(GraphicsPreparingDeviceSettings);

            //Load Camera
            LoadCamera();

            //Inizialize Physics system
            LoadPhysicsSystem();

            this.IsMouseVisible = false;

            //InitMainMenu();
            LoadComponents();

            graphics.MinimumPixelShaderProfile = ShaderProfile.PS_2_0;
            graphics.MinimumVertexShaderProfile = ShaderProfile.VS_3_0;

            // Construct our particle system components.
            explosionParticles = new ExplosionParticleSystem(this, Content);
            explosionSmokeParticles = new ExplosionSmokeParticleSystem(this, Content);
            projectileTrailParticles = new ProjectileTrailParticleSystem(this, Content);
            smokePlumeParticles = new SmokePlumeParticleSystem(this, Content);
            fireParticles = new FireParticleSystem(this, Content);

            // Set the draw order so the explosions and fire
            // will appear over the top of the smoke.
            smokePlumeParticles.DrawOrder = 100;
            explosionSmokeParticles.DrawOrder = 200;
            projectileTrailParticles.DrawOrder = 300;
            explosionParticles.DrawOrder = 400;
            fireParticles.DrawOrder = 500;


            // Register the particle system components.
            Components.Add(explosionParticles);
            Components.Add(explosionSmokeParticles);
            Components.Add(projectileTrailParticles);
            Components.Add(smokePlumeParticles);
            Components.Add(fireParticles);

        }








        #region Public Camera
        public DebugDrawer DebugDrawer
        {
            get { return debugDrawer; }
        }

        public Camera Camera
        {
            get { return camera; }
        }

        #endregion


        void UpdateExplosions(GameTime gameTime)
        {
            timeToNextProjectile -= gameTime.ElapsedGameTime;

            if (timeToNextProjectile <= TimeSpan.Zero)
            {
                // Create a new projectile once per second. The real work of moving
                // and creating particles is handled inside the Projectile class.
                projectiles.Add(new Projectile(explosionParticles,
                                               explosionSmokeParticles,
                                               projectileTrailParticles));

                timeToNextProjectile += TimeSpan.FromSeconds(1);
            }
        }

        void UpdateProjectiles(GameTime gameTime)
        {
            int i = 0;

            while (i < projectiles.Count)
            {
                if (!projectiles[i].Update(gameTime))
                {
                    // Remove projectiles at the end of their life.
                    projectiles.RemoveAt(i);
                }
                else
                {
                    // Advance to the next projectile.
                    i++;
                }
            }
        }

        void UpdateSmokePlume()
        {
            // This is trivial: we just create one new smoke particle per frame.
            //KeyboardState kb = new KeyboardState();

            //smokePlumeParticles.AddParticle(BotList[0].PhysicsBody.Position, Vector3.Zero);
        }


        protected override void Initialize()
        {

            SetResolution(sqconfig.ResolutionWidth, sqconfig.ResolutionHeight, sqconfig.Fullscreen);
            Window.Title = SqEngineInfo._full_version;

            #region CREATE TEST MAP

            /*
            IntroContent ico = new IntroContent();

            PresentationMessage pm = new PresentationMessage();
            ico.BackgroundSong = "Audio\\Soundtrack\\Apocalyptica-Path";


            pm.text = "{projectname} v{projectversion} ";
            pm.lifetime = 3000;
            pm.shadow = false;
            pm.text_color = Color.White;
            pm.animantion = PresentationType.MoveHorizForward;
            pm.position = GetCenterOfScreen();

            ico.IntroText.Add(pm);

            pm = new PresentationMessage();
            pm.text = "Project by:\nsquid <squid@stormwind.it>";
            pm.lifetime = 3000;
            pm.shadow = false;
            pm.text_color = Color.White;
            pm.animantion = PresentationType.MoveHorizForward;
            pm.position = GetCenterOfScreen();
            ico.IntroText.Add(pm);

            pm = new PresentationMessage();
            pm.text = "Build on powerful:\nXNA v3.1";
            pm.lifetime = 3000;
            pm.shadow = false;
            pm.text_color = Color.White;
            pm.animantion = PresentationType.MoveHorizForward;
            pm.position = GetCenterOfScreen();
            ico.IntroText.Add(pm);


            pm = new PresentationMessage();
            pm.text = "Homepage:\nhttp://squareengine.codeplex.com.";
            pm.lifetime = 3000;
            pm.shadow = false;
            pm.text_color = Color.White;
            pm.animantion = PresentationType.MoveHorizForward;
            pm.position = GetCenterOfScreen();
            ico.IntroText.Add(pm);

            pm = new PresentationMessage();
            pm.text = "If you want partecipate to build\nthis project contact me!";
            pm.lifetime = 3000;
            pm.text_color = Color.White;
            pm.shadow = false;
            pm.animantion = PresentationType.MoveHorizForward;
            pm.position = GetCenterOfScreen();
            ico.IntroText.Add(pm);



            pm = new PresentationMessage();
            pm.text = "I hope you enjoy this demo";
            pm.lifetime = 3000;
            pm.shadow = false;
            pm.animantion = PresentationType.MoveHorizForward;
            ico.IntroText.Add(pm);
            SaveMan.SaveIntro("c:\\temp.intro", ico);





            //SaveMan.SaveIntro("c:\\temp.intro", ico);
            
           /*
            
            

             
           //bwo.Name = "Box";
           //bwo.ObjectFilename = "box";
           //bwo.Texture = "Textures\\console_back";

          // SaveMan.SaveBasicWorldObject("c:\\box.bwo", bwo);

          // bwo = new BasicWorldObject();
           //bwo.Name = "Life Powerup";
          // bwo.ObjectFilename = "box";
          // bwo.Texture = "Textures\\Icons\\Life";

           //SaveMan.SaveBasicWorldObject("c:\\lifepowerup.bwo", bwo);
            
           MapObject map_obj = new MapObject();
           WorldObject wob = new WorldObject();
           BasicWorldObject bwo = new BasicWorldObject();

           map_obj.TerrainModel = "terrain2";
           map_obj.TerrainTexture = "Textures\\texture_3";

           //wob.ObjectType = WorldObjectType.SphereObject;
           //wob.BasicWorldObject = "\\BasicWorldObjects\\sfera.bwo";
           //wob.Params.Add("radius", 1.0f);

           //wob.Mass = 2.0f;
           //wob.Position = new Vector3(1, 1, 1);
           //wob.Rotation = new Vector3(2, 2, 2);
           //wob.Scale = 1;

           //map_obj.WorldObjects.Add(wob);
            

           wob = new WorldObject();
           wob.ObjectType = WorldObjectType.PowerUpObject;
           wob.BasicWorldObject =  "\\BasicWorldObjects\\lifepowerup.bwo";
           wob.Params.Add("sideLengths", new Vector3(1, 1, 1));
           wob.Params.Add("PowerObjectType", PowerupObjectType.LifePowerUp);
           wob.Params.Add("PowerObjectValue", 500);
           wob.Mass = 3.0f;
           wob.Position = new Vector3(-42, -12, 35);
           wob.Rotation = new Vector3(2, 2, 2);
           wob.Scale = 2;

           map_obj.WorldObjects.Add(wob);

           wob = new WorldObject();
           wob.ObjectType = WorldObjectType.PowerUpObject;
           wob.BasicWorldObject = "\\BasicWorldObjects\\ammopowerup.bwo";
           wob.Params.Add("sideLengths", new Vector3(1, 1, 1));
           wob.Params.Add("PowerObjectType", PowerupObjectType.AmmoPowerUp);
           wob.Params.Add("PowerObjectValue", 50);
           wob.Mass = 3.0f;
           wob.Position = new Vector3(-22, -12, -5);
           wob.Rotation = new Vector3(2, 2, 2);
           wob.Scale = 2;

           map_obj.WorldObjects.Add(wob);

           wob = new WorldObject();
           wob.ObjectType = WorldObjectType.PowerUpObject;
           wob.BasicWorldObject = "\\BasicWorldObjects\\armorpowerup.bwo";
           wob.Params.Add("sideLengths", new Vector3(1, 1, 1));
           wob.Params.Add("PowerObjectType", PowerupObjectType.ArmorPowerUp);
           wob.Params.Add("PowerObjectValue", 50);
           wob.Mass = 3.0f;
           wob.Position = new Vector3(13, -12, 25);
           wob.Rotation = new Vector3(2, 2, 2);
           wob.Scale = 2;

           map_obj.WorldObjects.Add(wob);

           wob = new WorldObject();
           wob.ObjectType = WorldObjectType.StaticObject;
           wob.BasicWorldObject = "\\BasicWorldObjects\\skyscraper.bwo";           
           wob.Mass = 3.0f;
           wob.Position = new Vector3(-34, -12, 20f);
           wob.Rotation = new Vector3(2, 2, 2);
           wob.Scale = 10;

           map_obj.WorldObjects.Add(wob);


           WorldBot wb = new WorldBot();

           wb.BotFile = "\\Bots\\T800.bot";
           wb.Orientation = new Vector3(-90f, 0, 0);
           wb.Position = new Vector3(1, 0, 0);

           map_obj.Bots.Add(wb);

           wb = new WorldBot();


           wb.BotFile =  "\\Bots\\area51.bot";
           wb.Orientation = new Vector3(-90f, 0, 0);
           wb.Position = new Vector3(1.5f, 0, 0);

           map_obj.Bots.Add(wb);


           //map_obj.Bots.Add(Content.RootDirectory + "\\Bots\\Martian.bot");


           map_obj.MapInfo.MapName = "Test";
           map_obj.MapInfo.Description = "Test map";
           map_obj.MapInfo.Author = "Squid";
           //map_obj.WorldObjects.Add(wob);

           //map_obj = SaveMan.LoadMap("c:\\temp.xml");
           //map_obj.Description = "ci";
           SaveMan.SaveMap("c:\\temp2.xml", map_obj);
         */




            #endregion
            base.Initialize();
        }


        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            InitAudioEngine();

            PrepareWorld();


            base.LoadContent();

        }
        protected override void UnloadContent()
        {
            content.Unload();           
            base.UnloadContent();
        }

        public void PrepareWorld()
        {
            InitPlayerWeapon();
            InitCrosshair();
            LoadHud();

        }



        #region Update


        bool leftButton = false;

        bool picking = false;
        Vector3 body_pick = new Vector3();
        // for picking
        float camPickDistance = 0.0f;
        bool middleButton = false;
        int oldWheel = 0;

        Stopwatch sw = new Stopwatch();

        private float GetExpAttraction(float len)
        {

            //if (len > 100)
            //{
            //    return 0.01f;
            //}
            //else
            //    if (len <= 99 && len >= 60)
            //    {
            //        return 0.02f;
            //    }
            //    else
            //        if (len <= 59 && len >= 30)
            //        {
            //            return 0.06f;
            //        }
            //if (len <= 29 && len >= 10)
            //{
            //    return 0.1f;
            //}
            //else
            //    if (len <= 9 && len >= 0)
            //    {
            //        return 0.3f;
            //    }
            //    else
            //        return 0.01f;

            return 0.001f;
        }


        protected override void Update(GameTime gameTime)
        {
            #region ThreadLoadMap
            if (MapState == MapLoadingState.None)
            {
                MapState = MapLoadingState.Loading;

                if (_map_to_load == "")
                    PrepareLoadMapThread(content.RootDirectory + _default_map);
                else
                    PrepareLoadMapThread(_map_to_load);

                msgs_sys.DrawOrder = 1;
                msgs_sys.QuickAdd(SqEngine.SqEngineInfo._full_version + " Loaded...", Color.Red, 1000, "");

                msgs_sys.Start();


                TargetMan = new TargetManager(this, camera, adcontent.LoadSpriteFont("Fonts/Calibri"));
                TargetMan.DrawOrder = 2;
                TargetMan.Start();
                this.Components.Add(TargetMan);


            }
            #endregion
            if (MapState == MapLoadingState.Loading)
            {
                crosshair.Enabled = false;
                hud.Enabled = false;
                fps_weapon.Enabled = false;


                contentloading_cmp.DrawOrder = 1;
                UI_cmd.DrawOrder = 1;
                gui_manager.DrawOrder = 1;
                fps_weapon.DrawOrder = 100;
                contentloading_cmp.UpdateLoadingText(MapStateString, Color.White);

            }

            if (MapState == MapLoadingState.JustLoaded)
            {
                LoadIntro(isIntroEnabled, IntroFile);
                MapState = MapLoadingState.Loaded;
                crosshair.Enabled = true;
                hud.Enabled = true;
                //fps_weapon.Enabled = true;

            }

            if (MapState == MapLoadingState.Loaded)
            {

                KeyboardState keyState = Keyboard.GetState();
                Microsoft.Xna.Framework.Input.MouseState mouseState = Mouse.GetState();

                keyboardmanager.Update(gameTime);

                UpdateSmokePlume();

                if (BotList.Count > 0)
                {
                    TargetMan.DrawOrder = 1;
                    TargetMan.UpdateTargetPos(BotList[0].PhysicsBody.Position, "");
                }



                if (sqconfig.ConsoleEnabled)
                    sqconsole.ConsoleInput(keyboardmanager.CheckActionKey(Actions.Player_Console));

                PlayerWantMenu(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_Menu)));


                cmp_gpssys.UpdatePosition(sqconfig.PlayerName, camera.Position);

                if (keyboardmanager.CheckKeyPressed(Keys.J) && !IsInputEnabled)
                {
                    BasicWorldObject box = SaveMan.LoadBasicWorldObject(@"Content\BasicWorldObjects\box.bwo");

                    ItmWebBox wb_object = new ItmWebBox(this, "Web Browser box", adcontent.LoadModel(Content.RootDirectory + "\\" + box.ObjectFilename), Matrix.Identity, 10.0f, camera.Position + Vector3.One);


                    //cmp_webbrowser.Visible = true;


                    //WebBrowserNavigate("http://www.youtube.com", false);

                    Components.Add(wb_object);
                    Worldobjlist.Add(wb_object);


                }

                if (keyboardmanager.CheckKeyPressed(Keys.K) && !IsInputEnabled)
                {
                    Vector3 ray = RayTo(mouseState.X, mouseState.Y);
                    BasicWorldObject box = SaveMan.LoadBasicWorldObject(@"Content\BasicWorldObjects\sfera.bwo");
                    ItmWebBox2d wb_object = new ItmWebBox2d(this, "Web Browser 2d", adcontent.LoadModel(Content.RootDirectory + "\\" + box.ObjectFilename), Matrix.Identity, 2.0f, camera.Position + Vector3.One);
                    
                    Components.Add(wb_object);
                    Worldobjlist.Add(wb_object);
                }

                if (keyboardmanager.CheckKeyPressed(Keys.L) && !IsInputEnabled)
                {

                    BasicWorldObject bwo = SaveMan.LoadBasicWorldObject(@"Content\BasicWorldObjects\terminal.bwo");
                    ItmTerminal s_object = new ItmTerminal(this, bwo.Name, adcontent.LoadModel(Content.RootDirectory + "\\" + bwo.ObjectFilename), Matrix.Identity, 1.0f, camera.Position + Vector3.One);
                    Components.Add(s_object);
                    Worldobjlist.Add(s_object);

                }
                if (!IsConsoleActive && !IsChatActive && !IsInputEnabled)
                {
                    TargetMan.EnableTargets(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_EnableTargets)));
                    screenshotmanager.CheckScreenshot(keyboardmanager.CheckActionKey(Actions.Player_Screenshot));
                    physStats.ShowHelp(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_EnableHelp)));
                    debugDrawer.CheckEnabled(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Debug_CollDrawer)));
                    camera.EnableWireframe(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Debug_Wireframe)));
                    cmp_scoreboard.ShowScoreBoard(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_EnableScore)));
                }

                if (!IsConsoleActive && !Guide.IsVisible && !IsInputEnabled)
                    chat_cmp.ChatEnable(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_Chat)));




                if (MapState != MapLoadingState.Loading && !introengine.Playing() && !IsInputEnabled)
                {
                    this.IsMouseVisible = IsGuiActive || IsInputEnabled;
                    crosshair.Enabled = !IsGuiActive;
                    fps_weapon.Enabled = !IsInputEnabled;
                }

                mediaplayer_sys.MediaPlayerControl(keyboardmanager.CheckActionPressed(keyState));
                mediaplayer_sys.EnabledRandom(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.MediaPlayer_Random)));
                mediaplayer_sys.NextSong(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.MediaPlayer_Next)));
                mediaplayer_sys.BackSong(keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.MediaPlayer_Back)));

                fps_weapon.Visible = !IsInputEnabled;

                CheckPlayerAction(mouseState.X, mouseState.Y);


                //DA fare perbenino..
                if (picking)
                {




                }
                #region Picking Objects with the mouse


                if (isPickEnabled)
                {
                    if (mouseState.MiddleButton == ButtonState.Pressed)
                    {
                        if (middleButton == false)
                        {
                            Vector3 ray = RayTo(mouseState.X, mouseState.Y);
                            float frac; CollisionSkin skin;
                            Vector3 pos, normal;

                            ImmovableSkinPredicate pred = new ImmovableSkinPredicate();

                            physicSystem.CollisionSystem.SegmentIntersect(out frac, out skin, out pos, out normal,
                                new Segment(camera.Position, ray * 1000.0f), pred);

                            if (skin != null && (skin.Owner != null))
                            {
                                if (!skin.Owner.Immovable)
                                {
                                    Vector3 delta = pos - skin.Owner.Position;
                                    delta = Vector3.Transform(delta, Matrix.Transpose(skin.Owner.Orientation));

                                    camPickDistance = (camera.Position - pos).Length();


                                    skin.Owner.SetActive();
                                    objectController.Destroy();
                                    damperController.Destroy();
                                    objectController.Initialise(skin.Owner, delta, pos);
                                    damperController.Initialise(skin.Owner, ConstraintVelocity.ReferenceFrame.Body, Vector3.Zero, Vector3.Zero);
                                    objectController.EnableConstraint();
                                    damperController.EnableConstraint();
                                }
                            }

                            middleButton = true;
                        }

                        if (objectController.IsConstraintEnabled && (objectController.Body != null))
                        {

                            if (!CheckBotCollisionSkin(objectController.Body.CollisionSkin))
                            {
                                Vector3 delta = objectController.Body.Position - camera.Position;
                                Vector3 ray = RayTo(mouseState.X, mouseState.Y); ray.Normalize();
                                // float deltaWheel = mouseState.ScrollWheelValue - oldWheel;

                                //                        float distance_attr = 20f;
                                //                        distance_attr  -=delta.Length();
                                camPickDistance -= GetExpAttraction(delta.Length());
                                Vector3 result = camera.Position + camPickDistance * ray;
                                oldWheel -= 1;
                                objectController.WorldPosition = result;
                                objectController.Body.SetActive();

                                picking = true;

                            }


                        }
                    }
                    else
                    {
                        //
                        if (objectController.Body != null)
                        {
                            objectController.Body.ClearForces();
                            objectController.DisableConstraint();
                            damperController.DisableConstraint();
                            body_pick = new Vector3();


                        }
                        middleButton = false;
                        picking = false;
                    }
                }
                #endregion


                if (keyState.IsKeyDown(Keys.F))
                {
                    body_pick.X += 0.1f;
                }

                hud.UpdateValues(_player.Life, _player.Armor, _player.MaxArmor, _player.Ammo, _player.MaxAmmo);

                UpdateTargetList(BotList);

                if (mouseState.LeftButton == ButtonState.Pressed && leftButton == false)
                {
                    if (!IsGuiActive && !IsConsoleActive && !IsInputEnabled)
                        Shoot();
                }
                if (mouseState.LeftButton == ButtonState.Released) leftButton = false;


                if (isPlayerEnabled && !IsConsoleActive && !IsInputEnabled)
                {
                    camera.IsMousePinned = true;
                    camera.EnableKeyboardInput = false;
                    camera.Position = character.PhysicsBody.Position + Vector3.Up;


                    Vector3 moveVector = new Vector3();
                    float amountOfMovement = 10.0f;

                    KeyboardState keys = Keyboard.GetState();


                    if (keyState.IsKeyDown(keyboardmanager.CheckActionKey(Actions.Player_StrafeRight)))
                        moveVector += Vector3.Right;
                    if (keyState.IsKeyDown(keyboardmanager.CheckActionKey(Actions.Player_StrafeLeft)))
                        moveVector += Vector3.Left;
                    if (keyState.IsKeyDown(keyboardmanager.CheckActionKey(Actions.Player_MoveBackwards)))
                        moveVector += Vector3.Backward;
                    if (keyState.IsKeyDown(keyboardmanager.CheckActionKey(Actions.Player_MoveForwards)))
                        moveVector += Vector3.Forward;

                    Matrix cameraRotation = Matrix.CreateRotationX(camera.Angles.X) *
                        Matrix.CreateRotationY(camera.Angles.Y);

                    moveVector = Vector3.Transform(moveVector, cameraRotation);

                    JiggleMath.NormalizeSafe(ref moveVector);
                    moveVector *= amountOfMovement;



                    //Run
                    if (keys.IsKeyUp(Keys.LeftShift) && keys.IsKeyUp(Keys.RightShift))
                    {
                        character.CharacterBody.DesiredVelocity = moveVector;
                    }
                    else
                    {
                        character.CharacterBody.DesiredVelocity = moveVector * 2;
                    }



                    if (keyState.IsKeyDown(keyboardmanager.CheckActionKey(Actions.Player_Jump)))
                    {
                        character.CharacterBody.DoJump();
                    }
                }

                else
                {
                    this.IsMouseVisible = true;
                    camera.EnableKeyboardInput = true;
                    camera.IsMousePinned = false;
                    crosshair.Visible = false;

                }



                timeStep = (float)gameTime.ElapsedGameTime.Ticks / TimeSpan.TicksPerSecond;


                //physicSystem.Integrate(timeStep);


                if (timeStep < 1.0f / 60.0f) physicSystem.Integrate(timeStep);
                else physicSystem.Integrate(1.0f / 60.0f);


            }


            base.Update(gameTime);
        }


        #endregion


        public void RestoreRenderState()
        {
            this.graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;
            this.graphics.GraphicsDevice.RenderState.AlphaTestEnable = true;
            this.graphics.GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
            this.graphics.GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;
            this.graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
        }

        private Vector3 RayTo(int x, int y)
        {
            Vector3 nearSource = new Vector3(x, y, 0);
            Vector3 farSource = new Vector3(x, y, 1);

            Matrix world = Matrix.CreateTranslation(0, 0, 0);

            Vector3 nearPoint = graphics.GraphicsDevice.Viewport.Unproject(nearSource, camera.Projection, camera.View, world);
            Vector3 farPoint = graphics.GraphicsDevice.Viewport.Unproject(farSource, camera.Projection, camera.View, world);

            Vector3 direction = farPoint - nearPoint;

            return direction;
        }


        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            smokePlumeParticles.SetCamera(camera.View, camera.Projection);

            base.Draw(gameTime);
        }

        private void LoadComponents()
        {
            //Load default config
            ConfigLoad(string.Empty);


            isIntroEnabled = sqconfig.IntroEnabled;
            IntroFile = sqconfig.IntroFile;

            isDebugEnabled = sqconfig.DebugMode;

            SetupKeys();

            wb_pool = new WebBrowserPool(this);

            debugDrawer = new DebugDrawer(this);
            debugDrawer.Enabled = false;
            debugDrawer.DrawOrder = 3;

            cmp_services = new GamerServicesComponent(this);


            audiomanager = new AudioManager(this, "Content");

            screenshotmanager = new ScreenShotComponent(this);

            award_cmp = new AwardsComponent(this, adcontent);

            msgs_sys = new MessagesSystem(this, adcontent);

            mediaplayer_sys = new MediaPlayerSystem(this, audiomanager, "", adcontent, SaveMan);
            mediaplayer_sys.DrawOrder = 1;

            LoadConsole();

            physStats = new FrameRateCounter(this, this.physicSystem, adcontent);
            physStats.DrawOrder = 2;

            contentloading_cmp = new ContentLoadingDrawer(this, adcontent, "", Color.White, "Fonts/Calibri", "");
            contentloading_cmp.DrawOrder = 1;

            chat_cmp = new ChatComponent(this, adcontent, sqconfig.PlayerName, "Fonts/Visitor", keyboardmanager);
            chat_cmp.Playername(sqconfig.PlayerName);
            chat_cmp.DrawOrder = 1;



            introengine = new PresentationSystem(this, adcontent);

            chat_handler = new ChatHandler(this, Color.Blue, "Textures/UI/chatTalking");


            gui_manager = new Manager(this, graphics, "Default", false);
            gui_manager.DrawOrder = 1;


            UI_cmd = new GUIComponent(this, adcontent, gui_manager, "");

            if (sqconfig.BloomEnabled)
            {
                eff_bloom = new BloomComponent(this, adcontent);
                eff_bloom.DrawOrder = 100;
            }

            cmp_gpssys = new GPSSystem(this, "Fonts/Calibri", adcontent);

            cmp_gpssys.DrawOrder = 1;
            cmp_gpssys.Active();

            cmp_scoreboard = new ScoreComponent(this, adcontent, "Fonts/Candara");
            cmp_scoreboard.DrawOrder = 1;

            cmp_webbrowser = new SqWebBrowserComponent(this, adcontent, 680, 480);
            cmp_webbrowser.DrawOrder = 1;



            this.Components.Add(adcontent);
            this.Components.Add(wb_pool);
            this.Components.Add(cmp_webbrowser);
            this.Components.Add(introengine);
            this.Components.Add(keyboardmanager);
            this.Components.Add(cmp_services);
            this.Components.Add(cmp_guidex);
            this.Components.Add(gui_manager);
            this.Components.Add(UI_cmd);
            this.Components.Add(physStats);
            this.Components.Add(screenshotmanager);
            this.Components.Add(camera);
            this.Components.Add(chat_cmp);
            this.Components.Add(contentloading_cmp);
            this.Components.Add(debugDrawer);
            this.Components.Add(award_cmp);
            this.Components.Add(msgs_sys);
            this.Components.Add(mediaplayer_sys);
            this.Components.Add(cmp_gpssys);
            this.Components.Add(cmp_scoreboard);




            // if (sqconfig.BloomEnabled)
            //this.Components.Add(eff_bloom);

            SetAntiAliasing(MultiSampleType.FourSamples, GraphicsAdapter.DefaultAdapter, SurfaceFormat.Rg32, new PresentationParameters());


        }



        #region HandlePlayerControl

        private void PlayerWantMenu(bool state)
        {
            if (state)
            {
                if (!UI_cmd.Active())
                {
                    camera.IsMousePinned = true;
                    UI_cmd.ShowMain();
                }
            }

        }

        private void PlayerWantExitGamepad(ButtonState gpb)
        {
            // Allows the game to exit
            if (gpb == ButtonState.Pressed)
                this.Exit();
        }



        #endregion



        private void LoadAudioContent()
        {
            audioEngine = new AudioEngine("Content/Audio/audio.xgs");
            waveBank = new WaveBank(audioEngine, "Content/Audio/Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content/Audio/Sound Bank.xsb");
            cue = soundBank.GetCue("m_health");



        }

        private void LoadPhysicsSystem()
        {
            physicSystem = new PhysicsSystem();

            physicSystem.CollisionSystem = new CollisionSystemGrid(32, 32, 32, 30, 30, 30);
            physicSystem.CollisionSystem = new CollisionSystemBrute();
            physicSystem.CollisionSystem = new CollisionSystemSAP();

            physicSystem.EnableFreezing = true;
            physicSystem.SolverType = PhysicsSystem.Solver.Normal;
            physicSystem.CollisionSystem.UseSweepTests = true;

            physicSystem.NumCollisionIterations = 8;
            physicSystem.NumContactIterations = 8;
            physicSystem.NumPenetrationRelaxtionTimesteps = 15;
        }

        private void LoadCamera()
        {
            camera = new Camera(this, keyboardmanager);
        }

        public void LoadIntro(bool introenabled, string filename)
        {
            IntroContent _introc = new IntroContent();
            if (introenabled)
            {
                if (filename != "")
                {
                    if (filename.Contains(":"))
                        _introc = SaveMan.LoadIntro(filename);
                    else
                        _introc = SaveMan.LoadIntro(Content.RootDirectory + "\\" + filename);

                }
            }


            if (introenabled)
            {
                audiomanager.LoadSong(_introc.BackgroundSong);

                if (fnt_miramo == null)
                    fnt_miramo = adcontent.LoadSpriteFont("Fonts\\Miramo");
                IntroContent intr = new IntroContent();


                for (int line = 0; line < _introc.IntroText.Count; line++)
                {
                    introengine.AddMessage(_introc.IntroText[line]);
                }


                introengine.OnStateChange += new PresentationSystem.ChangingHandler(introengine_OnStateChange);
                audiomanager.PlaySong(_introc.BackgroundSong);

                introengine.Start();
                isIntroPlaying = true;


            }

        }

        void introengine_OnStateChange(object sender, PresentationArgs ca)
        {
            if (ca.Message() == "stopped")
            {
                audiomanager.StopSong();
                isIntroPlaying = false;
            }
        }

        private void InitAudioEngine()
        {
            audioengine = new SqAudio("Content\\Audio\\audio.xgs");
            //audiomanager.LoadSong("Audio\\Soundtrack\\Apocalyptica-Path");

            cue = audioengine.GetCue("glass2");

        }

        public Vector2 GetCenterOfScreen()
        {
            Vector2 screenCenter = new Vector2(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight) / 2;
            return screenCenter;
        }


        private void Shoot()
        {

            if (!Guide.IsVisible)
            {
                Vector3 ray = camera.Position;
                PhysicObject physObj = fps_weapon.Shoot(camera.Position, Matrix.Identity);
                if (physObj != null)
                {
                    physObj.PhysicsBody.Mass = 10f;

                    physObj.PhysicsBody.Velocity = ((camera.Target - camera.Position) * 100f);
                    Components.Add(physObj);
                    leftButton = true;
                }

            }

        }


        private void InitSkydome(float theta)
        {
            if (theta == 0)
                theta = 3.82503986f;

            skydome = new SkyDome(this, ref camera, adcontent);
            skydome.DrawOrder = 0;
            skydome.Theta = theta;
            Components.Add(skydome);

            if (heightmapObj != null)
            {
                heightmapObj.SetSkydome(skydome, skydome.GetDayTexture, skydome.GetSunsetTexture, skydome.GetNightTexture, adcontent.LoadEffect("Effects\\Sky"));
            }

        }




        private void InitCrosshair()
        {
            Vector2 center = new Vector2();
            center.X = graphics.PreferredBackBufferHeight / 2;
            center.Y = graphics.PreferredBackBufferWidth / 2;
            camera.GameViewport = graphics.GraphicsDevice.Viewport;
            crosshair = new CrosshairSprite(this, camera, adcontent.LoadTexture2D("Textures/target"));
            crosshair.DrawOrder = 1;
            Components.Add(crosshair);

        }





        private void LoadHud()
        {
            hud = new Hud(this, adcontent, "Textures/Hud/LifeBar", "Textures/Icons/Armor", "Textures/Icons/Ammo");
            hud.LifePosition = new Vector2(GetSafeArea.X, GetSafeArea.Y + GetSafeArea.Height - 40);


            hud.DrawOrder = 1;
            hud.SetFont("Fonts/VerdanaBold");
            Components.Add(hud);
            hud.LifeValue = 1000;
        }

        public void SetResolution(int Width, int Height, bool fullscreen)
        {
            this.graphics.PreferredBackBufferHeight = Height;
            this.graphics.PreferredBackBufferWidth = Width;
            this.graphics.IsFullScreen = fullscreen;
            this.graphics.ApplyChanges();
            camera.RefreshAspectRatio(this);

        }

        public void SetupKeys()
        {
            keyboardmanager = new KeysManager(this);

            if (System.IO.File.Exists(Content.RootDirectory + "/Config/sqenginekeys.cfg"))
            {
                keyboardmanager.SetActionKeys = keyboardmanager.LoadFromFile(Content.RootDirectory + "/Config/sqenginekeys.cfg");

            }
            else
            {
                keyboardmanager.SetupKeyboardDefault(true);
                keyboardmanager.SaveKeysToFile(Content.RootDirectory + "/Config/sqenginekeys.cfg");

            }


        }


        public void InitPlayer(Vector3 start_position)
        {
            if (character == null)
            {
                character = new CharacterObject(this, start_position);
                this.Components.Add(character);
            }
            camera.Position = start_position;

            if (_player == null)
            {
                _player = new PlayerStats(this, 100, camera.Position, sqconfig.PlayerName);
                _player.Ammo = 30;
                _player.Weapon = SaveMan.LoadWeapon(Content.RootDirectory + "/Weapons/Machinegun.wpn");


            }
            else
            {
                _player.Life = 100;
                _player.Position = camera.Position;
                _player.Name = sqconfig.PlayerName;

            }
            UpdateLife(_player.Life);

        }

        public void InitPlayerWeapon()
        {

            fps_weapon = new FPSWeapon(this, camera, SaveMan.LoadWeapon(Content.RootDirectory + "/Weapons/Shotgun.wpn"), audiomanager, adcontent, false);
            fps_weapon.DrawOrder = 3;
            this.Components.Add(fps_weapon);


        }

        private void UpdateLife(int life)
        {
            hud.LifeValue = life;
        }

        public void PlaySound(string filename)
        {

            audiomanager.LoadSound(filename);
            audiomanager.PlaySound(filename);
        }



        public void UpdateTargetList(List<PK3_Model> botlist)
        {
            TargetMan.Targets = botlist;
        }

        public void AddAndPlayAward(Award award)
        {
            award_cmp.Awards.Add(award);
            award_cmp.UnlockAward(award_cmp.Awards[award_cmp.Awards.Count - 1]);

        }

        /// <summary>
        /// When player press action button and the distance from obj is lower 4.0
        /// execute PhysicObj.Action
        /// </summary>
        /// <param name="state">State of button</param>
        /// <param name="mouse_x"></param>
        /// <param name="mouse_y"></param>
        public void CheckPlayerAction(int mouse_x, int mouse_y)
        {
            Vector3 ray = RayTo(mouse_x, mouse_y);
            float frac;
            CollisionSkin skin;
            Vector3 pos, normal;

            ImmovableSkinPredicate pred = new ImmovableSkinPredicate();

            physicSystem.CollisionSystem.SegmentIntersect(out frac, out skin, out pos, out normal,
                new Segment(camera.Position, ray * 1000.0f), pred);


            if (skin != null && (skin.Owner != null))
            {
                BasicObject pyo = GetObjFromSkin(skin);
                if (pyo != null)
                {
                    float distance = Distance.PointPointDistance(pyo.PhysicsBody.Position, camera.Position);

                    bool state = keyboardmanager.CheckKeyPressed(keyboardmanager.CheckActionKey(Actions.Player_Action));
                    
                    if (distance <= pyo.ActionDistance && state || pyo.ActionDistance == -1 && state)
                    {
                        pyo.Action(CurrentPlayer);

                    }

                    pyo.MouseOver(distance, ray, pos, normal, frac);

                    prev_obj = pyo;

                    if (pyo != prev_obj && prev_obj != null)
                    {
                        prev_obj.MouseOver(distance, ray, pos, normal, frac);
                    }



                }

            }
            else
            {
                if (prev_obj != null)
                {
                    prev_obj.MouseLeave(0.0f, ray, pos, normal, frac);
                    prev_obj = null;
                }
            }
            //}

        }

        private BasicObject GetObjFromSkin(CollisionSkin ColSkin)
        {
            BasicObject phyobj = null;
            for (int i = 0; i < Worldobjlist.Count; i++)
            {
                if (ColSkin == Worldobjlist[i].PhysicsSkin)
                    phyobj = Worldobjlist[i];
            }

            return phyobj;
        }






    }
}



